using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Reflection;
using System.Xml;

using Gonte.Reflection;

namespace Gonte.Configuration
{
    /// <summary>
    /// Class libraries don't have any configuration file associated with it.
    /// Therefore we are implementing our own
    /// </summary>
    public sealed class ClassLibraryConfigurationManager
    {
        #region Constructors

        static ClassLibraryConfigurationManager()
        {
            configurations_ = new Dictionary<string, ClassLibraryConfiguration>();

            AppDomain currentDomain = AppDomain.CurrentDomain;
            Assembly[] assemblies = currentDomain.GetAssemblies();

            foreach (Assembly assembly in assemblies)
            {
                string assemblyName = assembly.FullName.ToLower();
                if (!assemblyName.StartsWith("system")
                    && !assemblyName.StartsWith("mscorlib")
                    && !assemblyName.StartsWith("microsoft")) // Remove this if Microsoft starts using my manager :-)
                {
                    ClassLibraryConfigurationAttribute configAttribute = GetConfigurationAttribute(assembly);
                    if (configAttribute != null)
                    {
                        ClassLibraryConfiguration config = new ClassLibraryConfiguration();

                        XmlDocument xmlDoc = new XmlDocument();

                        if (configAttribute.IsEmbeddeded)
                        {
                            string xml = EmbeddedResource.GetString(assembly, configAttribute.Path);
                            xmlDoc.LoadXml(xml);
                        }
                        else
                        {
                            xmlDoc.Load(configAttribute.Path);
                        }

                        config.Load(xmlDoc);
                        configurations_[assembly.FullName] = config;
                    }
                }
            }
        } 

        #endregion

        #region Methods

        public static Object GetSection(string sectionName, Type type)
        {
            if (type == null)
            {
                return GetSection(sectionName, string.Empty);
            }

            Assembly assembly = Assembly.GetAssembly(type);
            if (assembly == null)
            {
                throw new ConfigurationErrorsException(string.Format("Unable to find assembly for type: {0}", type.ToString()));
            }

            ClassLibraryConfigurationAttribute configAttribute = GetConfigurationAttribute(assembly);
            if (configAttribute == null) // No configuration attribute found, call the standard configuration manager
            {
                return GetSection(sectionName, string.Empty);
            }

            return GetSection(sectionName, assembly.FullName);
        }

        public static Object GetSection(string sectionName, string key)
        {
            Object section = null;

            // If the key is not provided or does not exist use the standard configuration manager
            if (string.IsNullOrEmpty(key)
                || !configurations_.ContainsKey(key))
            {
                // TODO: Add the possibility of searching for a specific section name in all the libraries
                section = ConfigurationManager.GetSection(sectionName);
                if (section == null)
                {
                    return null;
                    //throw new ConfigurationErrorsException(string.Format("Unable to find configuration section of name: {0}", sectionName));
                }
                return section;
            }

            section = configurations_[key].GetSection(sectionName);
            if (section == null)
            {
                throw new ConfigurationErrorsException(string.Format("Unable to find configuration section of name: {0}", sectionName));
            }
            return section;
        }

        public static void RefreshSection(string sectionName)
        {
            throw new NotImplementedException();
        } 

        #endregion

        #region Properties

        public static NameValueCollection AppSettings
        {
            get { return null; }
        }

        public static ConnectionStringSettingsCollection ConnectionStrings
        {
            get { return null; }
        }

        #endregion

        #region Helpers

        private static ClassLibraryConfigurationAttribute GetConfigurationAttribute(Assembly assembly)
        {
            ClassLibraryConfigurationAttribute configAttribute = null;

            Object[] attributes = assembly.GetCustomAttributes(typeof(ClassLibraryConfigurationAttribute), false);

            if (attributes != null
                && attributes.Length > 0)
            {
                configAttribute = attributes[0] as ClassLibraryConfigurationAttribute;
            }

            return configAttribute;
        }

        #endregion

        #region Fields

        private static Dictionary<string, ClassLibraryConfiguration> configurations_; 

        #endregion
    }
}
